import tkinter as tk
import tkinter.messagebox
import hashlib
import json
import time
import torch
import torchcsprng as csprng
import pymysql
import random

# 窗口
window = tk.Tk()
window.title('学生挂科补考查询系统')
window.geometry('300x280')
# 画布放置图片
canvas = tk.Canvas(window, height=120, width=300)
imagefile = tk.PhotoImage(file='bj.png')
image = canvas.create_image(0, 0, anchor='nw', image=imagefile)
canvas.pack(side='top')
# 标签 用户名密码
tk.Label(window, text='用户名:').place(x=40, y=150)
tk.Label(window, text='密码:').place(x=40, y=190)
# 用户名输入框
var_usr_name = tk.StringVar()
entry_usr_name = tk.Entry(window, width=24, textvariable=var_usr_name)
entry_usr_name.place(x=85, y=150)
# 密码输入框
var_usr_pwd = tk.StringVar()
entry_usr_pwd = tk.Entry(window, width=24, textvariable=var_usr_pwd, show='*')
entry_usr_pwd.place(x=85, y=190)



# 存储密码的步骤
# 使用CSPRNG生成一个长度足够的盐值
# 将盐值混入密码，并使用标准的加密哈希函数进行加密，如SHA256
# 把哈希值和盐值一起存入数据库中对应此用户的那条记录

# 校验密码的步骤
# 从数据库取出用户的密码哈希值和对应盐值
# 将盐值混入用户输入的密码，并且使用同样的哈希函数进行加密
# 比较上一步的结果和数据库储存的哈希值是否相同，如果相同那么密码正确，反之密码错误

# 用户注册功能函数
class UserRegiste(object):

  def __init__(self):
    self.db = pymysql.connect(host='212.64.6.46', port=3306, user='json', passwd='123456', db='json')
    self.cursor = self.db.cursor()
    self.prem(self.db)

  def prem(self, db):
    self.cursor.execute("SELECT VERSION()")
    data = self.cursor.fetchone()
    print("Database version : %s " % data)  # 结果表明已经连接成功
    # 创建表单
    # self.cursor.execute("DROP TABLE IF EXISTS jsondb")
    # sql = """create table jsondb(
    # time varchar(100) not null,
    # username varchar(255) not null,
    # password varchar(255) not null,
    # salt varchar(255) not null)"""
    # self.cursor.execute(sql)

  def db_write(self, username, password):
    dict = {'time': 'Null', 'username': 'Null', 'password': 'Null', 'salt': 'Null'}
    times = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    mt19937_gen = csprng.create_mt19937_generator()
    salt = torch.empty(10, dtype=torch.int64, device='cpu').random_(torch.iinfo(torch.int64).min, to=None, generator=mt19937_gen)
    index = random.randint(0, 9)
    Salt = salt[index].item()
    pwd = password + str(Salt)
    password_real = hashlib.sha256(pwd.encode("utf-8")).hexdigest()

    dict['time'] = times
    dict['username'] = username
    dict['password'] = password_real
    dict['salt'] = str(Salt)

    result = []
    result.append((dict['time'], dict['username'], dict['password'], dict['salt']))
    inesrt_re = "insert into jsondb(time, username, password, salt) values(%s,%s,%s,%s)"
    self.cursor.executemany(inesrt_re, result)
    print('Register successfully!')
    self.db.commit()

# 用户登录功能函数
class UserLogin(object):

  def __init__(self):
    self.db = pymysql.connect(host='212.64.6.46', port=3306, user='json', passwd='123456', db='json')
    self.cursor = self.db.cursor()

  def check_password(self, username, password):
    flag = False
    self.i = 0
    self.cursor.execute('select username, password, salt from jsondb')
    result = self.cursor.fetchall()
    while True:
      for self.i in range(len(result)):
        if result[self.i][0] == username:
          pwd = password + str(result[self.i][2])
          password_check = hashlib.sha256(pwd.encode("utf-8")).hexdigest()
          if password_check == result[self.i][1]:
            flag = True
            self.i = 0
            break
        else:
          self.i = self.i + 1
      self.i = 0
      break

    if flag == True:
      print('Login Success!')
    else:
      print('Invalid username or password...')

    return flag

# 标签登录函数
def usr_log_in():
    # 实例化对象
    log = UserLogin()

    # 输入框获取用户名密码
    usr_name = var_usr_name.get()
    usr_pwd = var_usr_pwd.get()

    # 用户名密码不能为空
    if usr_name == '' or usr_pwd == '':
        tk.messagebox.showerror(message='用户名或密码为空')
        flag = False
    else:
        flag = True

    # 判断用户名和密码是否匹配
    if flag == True:
        if log.check_password(usr_name, usr_pwd) == True:
            tk.messagebox.showinfo(title='welcome', message='欢迎您：' + usr_name)
        else:
            tk.messagebox.showerror(message='账号或密码输入错误')

# 标签找回密码函数
def usr_sign_quit():
    tkinter.messagebox.showerror('学业预警通知书', '车到山前必有坑，船到桥头自然沉。')

# 标签注册函数
def usr_sign_up():
    log = UserLogin()
    reg = UserRegiste()

    # 确认注册时的相应函数
    def signtowcg():
        # 获取输入框内的内容
        nn = new_name.get()
        np = new_pwd.get()
        npf = new_pwd_confirm.get()

        # 检查用户名存在、密码为空、密码前后不一致
        if np == '' or nn == '':
            tk.messagebox.showerror('错误', '用户名或密码为空')
            flag = False
        elif np != npf:
            tk.messagebox.showerror('错误', '密码前后不一致')
            flag = False
        else:
            flag = True

        if flag == True:
            # 本地加载已有用户信息,如果没有则已有用户信息为空
            if log.check_password(nn, npf) == True:
                tk.messagebox.showerror('错误', '用户名已存在')
            # 注册信息没有问题则将用户名密码写入数据库
            else:

                reg.db_write(nn, npf)
                tk.messagebox.showinfo('欢迎', '用户：' + nn + '，注册成功！')
                # 注册完成关闭窗口
                window_sign_up.destroy()


    # 新建注册界面
    window_sign_up = tk.Toplevel(window)
    window_sign_up.geometry('300x150')
    window_sign_up.title('用户注册')
    # 用户名变量及标签、输入框
    new_name = tk.StringVar()
    tk.Label(window_sign_up, text='用户名：').place(x=10, y=10)
    tk.Entry(window_sign_up, textvariable=new_name, width=23).place(x=120, y=10)
    # 密码变量及标签、输入框
    new_pwd = tk.StringVar()
    tk.Label(window_sign_up, text='请输入密码：').place(x=10, y=45)
    tk.Entry(window_sign_up, textvariable=new_pwd, show='*', width=23).place(x=120, y=45)
    # 重复密码变量及标签、输入框
    new_pwd_confirm = tk.StringVar()
    tk.Label(window_sign_up, text='请再次输入密码：').place(x=10, y=80)
    tk.Entry(window_sign_up, textvariable=new_pwd_confirm, show='*', width=23).place(x=120, y=80)
    # 确认注册按钮及位置
    bt_confirm_sign_up = tk.Button(window_sign_up, text='确认注册', width=30, fg="white", bg='green', command=signtowcg)
    bt_confirm_sign_up.place(x=40, y=115)

    window_sign_up.iconbitmap("tmp.ico")
    window_sign_up.resizable(0,0)


# 登录 注册按钮
bt_login = tk.Button(window, text='登录', width=30, fg="white", bg='red', command=usr_log_in)
bt_login.place(x=40, y=220)
bt_logup = tk.Button(window, text='忘记密码？', bg='#F0F0F0', fg="orange", bd=0, command=usr_sign_quit)
bt_logup.place(x=145, y=250)
bt_logup = tk.Button(window, text='立即注册', bg='#F0F0F0', fg="blue", bd=0, command=usr_sign_up)
bt_logup.place(x=210, y=250)

# 禁止拉伸窗口
window.resizable(0,0)

# 设置窗口图标
window.iconbitmap("tmp.ico")

# 主循环
window.mainloop()